<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
   ______                  __  __
  / ____/___  __  ______  / /_/ /_  __
 / /   / __ \/ / / / __ \/ __/ / / / /
/ /___/ /_/ / /_/ / / / / /_/ / /_/ /
\____/\____/\__,_/_/ /_/\__/_/\__, /
              http://count.ly/____/
-->
<html>
<head> 
	<title><%- countly.title %></title> 
	<meta name="viewport" content="width=device-width, user-scalable=0, maximum-scale=1.0">
    <meta name="robots" content="noindex">
	<link rel="icon" type="image/png" href="<%- cdn %>images/favicon.png">
    <link rel="stylesheet" href="<%- cdn %>stylesheets/font-awesome/css/font-awesome.min.css" />
    <link rel="stylesheet" href="<%- cdn %>stylesheets/ionicons/css/ionicons.min.css" />
    <link rel="stylesheet" href="<%- cdn %>stylesheets/material/material-icons.css" />
	<link rel="stylesheet" href="<%- cdn %>javascripts/dom/jqueryui/jquery.ui.base.css" />
	<link rel="stylesheet" href="<%- cdn %>javascripts/dom/jqueryui/jquery.ui.theme.css" />
    <link rel="stylesheet" href="<%- cdn %>stylesheets/main.min.css?<%= countly.version %>" />
    <link rel="stylesheet" href="<%- cdn %>crashes/stylesheets/main.css?<%= countly.version %>" />
    <script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/min/countly.dom.js?<%= countly.version %>"></script>
    <script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/utils/moment/moment-with-locales.min.js?<%= countly.version %>"></script>
    <script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/utils/underscore-min.js?<%= countly.version %>"></script>
    <script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/utils/handlebars.js?<%= countly.version %>"></script>
    <script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/utils/jquery.i18n.properties-min-1.0.9.js?<%= countly.version %>"></script>
    <script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/utils/highlight/highlight.pack.js?<%= countly.version %>"></script>
    <style>
        #content-container { margin: 0; position: relative; }
        #content { padding: 0; position: relative; }
        .back-link { display: none; }
        #countly-promo { text-align: center; padding: 20px; border: 1px solid #d0d0d0; margin: 16px; border-radius: 2px; background-color: #FFF; margin-bottom: 0; color: #2FA732; font-size: 15px; font-weight: 100; }
    </style>
</head>
<body> 
    <% if (countly.page && countly.title.indexOf("Countly") !== -1){ %>
    <h3 id="countly-promo">This crash report is generated by Countly. Get your own Countly Analytics and Marketing Platform <a href="<%- countly.page %>" target="_blank" style="text-decoration: underline;">here</a>.</h3>
     <% } %>
	<div id="overlay"></div>
    <div id="cly-resource" class="dialog black" style="max-width: 800px; max-height: 600px;">
        <div class="content"></div>
    </div>
	<div id="cly-popup" class="dialog black">
		<div class="indicator"></div>
		<div class="content"></div>
	</div>
	<div id="cly-loading" class="dialog black"> 
 		<div class="indicator"></div> 
 		<div class="message"></div> 
 		<div class="content"></div>
 	</div> 
	<div id="cly-alert" class="dialog">
		<div class="indicator"></div>
		<div class="message"></div>
		<div class="buttons">
				<a id="dialog-ok" class="icon-button light" data-localize="common.ok"></a>
		</div>
	</div>
	<div id="cly-confirm" class="dialog">
		<div class="indicator"></div>
		<div class="message"></div>
		<div class="buttons">
				<a id="dialog-continue" class="icon-button light" data-localize="common.continue"></a>
				<a id="dialog-cancel" class="icon-button light" data-localize="common.cancel"></a>
		</div>
	</div>
    <div id="content-container">
        <div id="content-top"></div>
        <div id="content"></div>
    </div>
    <script>
    window.countlyGlobal = window.countlyGlobal || {};
    countlyGlobal["path"] = "<%- path %>";
    countlyGlobal["cdn"] = "<%- cdn %>";
    countlyGlobal["member"] = {};
    store = {get:function(){return null;}, set:function(){}};
    </script>
    <script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/countly/countly.helpers.js?<%= countly.version %>"></script>
    <script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/countly/countly.common.js?<%= countly.version %>"></script>
    <script>
    jQuery.i18n.properties({
        name:'locale',
        cache:true,
        language:countlyCommon.BROWSER_LANG_SHORT,
        path:[countlyGlobal["cdn"]+'localization/min/'],
        mode:'map'
    });
    Handlebars.registerHelper('getFormattedNumber', function (context, options) {
        if (isNaN(context)) {
            return context;
        }

        ret = parseFloat((parseFloat(context).toFixed(2)).toString()).toString();
        return ret.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
    });
    Handlebars.registerHelper('eachOfObject', function (context, options) {
        var ret = "";
        for (var prop in context) {
            ret = ret + options.fn({property:prop, value:context[prop]});
        }
        return ret;
    });
    
    function localize() {

        var helpers = {
            onlyFirstUpper:function (str) {
                return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
            },
            upper:function (str) {
                return str.toUpperCase();
            }
        };

        // translate help module
        $("[data-help-localize]").each(function () {
            var elem = $(this);
            if (elem.data("help-localize") != undefined) {
                elem.data("help", jQuery.i18n.map[elem.data("help-localize")]);
            }
        });

        // translate dashboard
        $("[data-localize]").each(function () {
            var elem = $(this),
                toLocal = elem.data("localize").split("!"),
                localizedValue = "";

            if (toLocal.length == 2) {
                if (helpers[toLocal[0]]) {
                    localizedValue = helpers[toLocal[0]](jQuery.i18n.map[toLocal[1]]);
                } else {
                    localizedValue = jQuery.i18n.prop(toLocal[0], jQuery.i18n.map[toLocal[1]]);
                }
            } else {
                localizedValue = jQuery.i18n.map[elem.data("localize")];
            }

            if (elem.is("input[type=text]") || elem.is("input[type=password]") || elem.is("textarea")) {
                elem.attr("placeholder", localizedValue);
            } else if (elem.is("input[type=button]") || elem.is("input[type=submit]")) {
                elem.attr("value", localizedValue);
            } else {
                elem.text(localizedValue);
            }
        });
    };
    </script>
	<script language="javascript" type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/countly/countly.config.js?<%= countly.version %>"></script>
    <script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/countly/countly.device.list.js?<%= countly.version %>"></script>
	<script language="javascript" type="text/javascript" src="<%- cdn %>javascripts/min/countly.visualization.js?<%= countly.version %>"></script>
	<script language="javascript" type="text/javascript" src="<%- cdn %>crashes/javascripts/countly.models.js?<%= countly.version %>"></script>
	<script>
    var crash_data = <%-JSON.stringify(data)%>;
window.CrashgroupView = {
    beforeRender: function() {
		var self = this;
		return $.when($.get(countlyGlobal["path"]+'/crashes/templates/crashgroup.html', function(src){
			self.template = Handlebars.compile(src);
		})).then(function () {self.renderCommon()});
    },
    renderCommon:function (isRefresh) {

        var crashData = countlyCrashes.getGroupData();
		crashData.latest_version = crashData.latest_version.replace(/:/g, '.');
		this.metrics = countlyCrashes.getMetrics();
        for(var i in this.metrics){
            for(var j in this.metrics[i]){
                this.curMetric = j;
                this.curTitle = this.metrics[i][j];
                break;
            }
            break;
        }

        this.templateData = {
            "page-title":jQuery.i18n.map["crashes.crashes-by"],
            "note-placeholder": jQuery.i18n.map["crashes.editnote"],
			"data":crashData,
            "external": true,
			"error":crashData.name,
            "fatal": (crashData.nonfatal) ? jQuery.i18n.map["crashes.nonfatal"] : jQuery.i18n.map["crashes.fatal"],
			"active-segmentation": this.curTitle,
			"segmentations": this.metrics,
			"big-numbers":{
                "class":"four-column",
                "items":[
					{
                        "title":jQuery.i18n.map["crashes.platform"],
                        "total":crashData.os,
                        "help":"crashes.help-platform"
                    },
                    {
                        "title":jQuery.i18n.map["crashes.reports"],
                        "total":crashData.reports,
                        "help":"crashes.help-reports"
                    },
					{
                        "title":jQuery.i18n.map["crashes.highest-version"],
                        "total":crashData.latest_version.replace(/:/g, '.'),
                        "help":"crashes.help-app-version"
                    }
                ]
            },
            "bars":[
                {
                    "title":jQuery.i18n.map["crashes.root"],
                    "data": countlyCrashes.getBoolBars("root"),
                    "help":"crashes.help-root"
                },
				{
                    "title":jQuery.i18n.map["crashes.online"],
                    "data":countlyCrashes.getBoolBars("online"),
                    "help":"crashes.help-online"
                },
                {
                    "title":jQuery.i18n.map["crashes.muted"],
                    "data": countlyCrashes.getBoolBars("muted"),
                    "help":"crashes.help-muted"
                },
				{
                    "title":jQuery.i18n.map["crashes.background"],
                    "data": countlyCrashes.getBoolBars("background"),
                    "help":"crashes.help-background"
                }
            ]
        };
        if(crashData.ram){
            this.templateData["ranges"] = [
				{
                    "title":jQuery.i18n.map["crashes.ram"],
					"icon":"memory",
                    "help":"crashes.help-ram",
                    "min":crashData.ram.min+" %",
                    "max":crashData.ram.max+" %",
                    "avg":(crashData.ram.total/crashData.ram.count).toFixed(2)+" %"
                },
				{
                    "title":jQuery.i18n.map["crashes.disk"],
					"icon":"sd_storage",
                    "help":"crashes.help-disk",
                    "min":crashData.disk.min+" %",
                    "max":crashData.disk.max+" %",
                    "avg":(crashData.disk.total/crashData.disk.count).toFixed(2)+" %"
                },
				{
                    "title":jQuery.i18n.map["crashes.battery"],
					"icon":"battery_full",
                    "help":"crashes.help-battery",
                    "min":crashData.bat.min+" %",
                    "max":crashData.bat.max+" %",
                    "avg":(crashData.bat.total/crashData.bat.count).toFixed(2)+" %"
                },
				{
                    "title":jQuery.i18n.map["crashes.run"],
					"icon":"play_arrow",
                    "help":"crashes.help-run",
                    "min":countlyCommon.timeString(crashData.run.min/60),
                    "max":countlyCommon.timeString(crashData.run.max/60),
                    "avg":countlyCommon.timeString((crashData.run.total/crashData.run.count)/60)
                }
            ];
        }
        if(crashData.users){
            this.templateData["big-numbers"]["items"].push({
                "title":jQuery.i18n.map["crashes.affected-users"],
                "total":crashData.users + " ("+((crashData.users/crashData.total)*100).toFixed(2)+"%)",
                "help":"crashes.help-affected"
            });
        }
        if(crashData.loss){
            this.templateData["loss"] = true;
            this.templateData["big-numbers"]["items"].push({
                "title":jQuery.i18n.map["crashes.loss"],
                "total":crashData.loss,
                "help":"crashes.help-loss"
            });
        }
        if(this.templateData["big-numbers"]["items"].length == 3)
            this.templateData["big-numbers"]["class"] = "three-column";
        else if(this.templateData["big-numbers"]["items"].length == 5)
            this.templateData["big-numbers"]["class"] = "five-column";
        if(crashData.session){
            this.templateData["frequency"] = true;
            if(this.templateData["ranges"])
                this.templateData["ranges"].push({
                    "title":jQuery.i18n.map["crashes.sessions"],
                    "icon":"repeat",
                    "help":"crashes.help-frequency",
                    "min":crashData.session.min,
                    "max":crashData.session.max,
                    "avg":((Math.round(crashData.session.total/crashData.session.count)*100)/100)
                });
        }
        $('#content').html(this.template(this.templateData));
        var self = this;
        $(".segmentation-option").on("click", function () {
			self.switchMetric($(this).data("value"));
		});
        if(crashData.data){
            this.dtable = $('.d-table').dataTable($.extend({}, $.fn.dataTable.defaults, {
                "aaData": crashData.data,
				"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
					$(nRow).attr("id", aData._id);
				},
                "aoColumns": [
					{ "mData": function(row, type){if(type == "display") return countlyCommon.formatTimeAgo(row.ts); else return row.ts;}, "sType":"format-ago", "sTitle": jQuery.i18n.map["crashes.crashed"]},
					{ "mData": function(row, type){return row.os + " " + row.os_version.replace(/:/g, '.');}, "sType":"string", "sTitle": jQuery.i18n.map["crashes.os_version"] },
					{ "mData": function(row, type){var str = ""; if(row.manufacture) str += row.manufacture+" "; if(row.device) str += countlyDeviceList[row.device] || row.device; return str;}, "sType":"string", "sTitle": jQuery.i18n.map["crashes.device"]},
					{ "mData": function(row, type){return row.app_version.replace(/:/g, '.');}, "sType":"string", "sTitle": jQuery.i18n.map["crashes.app_version"] }
                ]
            }));
			this.dtable.stickyTableHeaders();
			this.dtable.fnSort( [ [0,'desc'] ] );
			CountlyHelpers.expandRows(this.dtable, this.formatData);
        }
		countlyCommon.drawGraph(crashData.dp[this.curMetric], "#dashboard-graph", "bar");
        localize();
        $('.help-zone-vb').tipsy({gravity:$.fn.tipsy.autoNS, trigger:'manual', title:function () {
            return ($(this).data("help")) ? $(this).data("help") : "";
        }, fade:true, offset:5, cssClass:'yellow', opacity:1, html:true});
        $('.help-zone-vs').tipsy({gravity:$.fn.tipsy.autoNS, trigger:'manual', title:function () {
            return ($(this).data("help")) ? $(this).data("help") : "";
        }, fade:true, offset:5, cssClass:'yellow narrow', opacity:1, html:true});
        $(".help-zone-vs, .help-zone-vb").hover(
            function () {
                $(this).tipsy("show");
            },
            function () {
                $(this).tipsy("hide");
            }
        );

        var pre = $(".crash-stack pre")[0];
        pre.innerHTML = '<span class="line-number"></span>' + pre.innerHTML + '<span class="cl"></span>';
        var num = pre.innerHTML.split(/\n/).length;
        for (var i = 0; i < num; i++) {
            var line_num = pre.getElementsByTagName('span')[0];
            line_num.innerHTML += '<span>' + (i + 1) + '</span>';
        }

        $("#expand-crash").on("click", function() {
            $(this).toggleClass("active");
            $("#expandable").toggleClass("collapsed");
        });

        var errorHeight = $("#expandable").find("code").outerHeight();

        if (errorHeight < 200) {
            $("#expandable").removeClass("collapsed");
            $("#expand-crash").hide();
        } else {
            $("#expandable").addClass("collapsed");
            $("#expand-crash").show();
        }

        $("document").ready(function() {
            $('pre code').each(function(i, block) {
                if(typeof hljs != "undefined"){
                    hljs.highlightBlock(block);
                }
            });
        });
    },
	formatData: function( data ) {
		// `d` is the original data object for the row
		var str = '';
		if(data){
			str += '<div class="datatablesubrow">'+
				'<table style="width: 100%;">'+
						'<tr>'+
							'<td class="text-left">'+jQuery.i18n.map["crashes.app_version"]+':</td>'+
							'<td class="text-left">'+jQuery.i18n.map["crashes.device"]+':</td>'+
							'<td class="text-left">'+jQuery.i18n.map["crashes.state"]+':</td>';
                            if(data.custom)
                                str += '<td class="text-left">'+jQuery.i18n.map["crashes.custom"]+':</td>';
                            if(data.logs)
                                str += '<td class="text-left">'+jQuery.i18n.map["crashes.logs"]+':</td>';
						str += '</tr>'+
						'<tr>'+
							'<td class="text-right">'+data.app_version.replace(/:/g, '.')+'</td>'+
							'<td class="text-right">'+data.os+' ';
                                if(data.os_version)
                                    str += data.os_version.replace(/:/g, '.')+'<br/>';
                                if(data.manufacture)
                                    str += data.manufacture;+' ';
                                if(data.manufacture)
                                    str += data.device;
                                if(data.cpu)
                                    str += ' ('+data.cpu+')'+'<br/>';
                                if(data.opengl)
                                    str += jQuery.i18n.map["crashes.opengl"]+': '+data.opengl+'<br/>';
                                if(data.resolution)
                                    str += jQuery.i18n.map["crashes.resolution"]+': '+data.resolution+'<br/>';
                                str += jQuery.i18n.map["crashes.root"]+': '+((data.root)? "yes" : "no")+'<br/>';
                            str += '</td>'+
                            '<td class="text-left">';
                                if(data.ram_current && data.ram_total)
                                    str += jQuery.i18n.map["crashes.ram"]+': '+data.ram_current+'/'+data.ram_total+' Mb<br/>';
                                if(data.disk_current && data.disk_total)
                                    str += jQuery.i18n.map["crashes.disk"]+': '+data.disk_current+'/'+data.disk_total+' Mb<br/>';
                                if(data.bat_current)
                                    str += jQuery.i18n.map["crashes.battery"]+': '+data.bat_current+'%<br/>';
                                if(data.run)
                                    str += jQuery.i18n.map["crashes.run"]+': '+countlyCommon.timeString(data.run/60)+'<br/>';
                                if(data.session)
                                    str += jQuery.i18n.map["crashes.after"]+' '+data.session+' '+jQuery.i18n.map["crashes.sessions"]+'<br/>';
                                else
                                    str += jQuery.i18n.map["crashes.frequency"]+': '+jQuery.i18n.map["crashes.first-crash"]+'<br/>';
                                str += jQuery.i18n.map["crashes.online"]+":"+((data.online)? "yes" : "no")+"<br/>";
                                str += jQuery.i18n.map["crashes.background"]+":"+((data.background)? "yes" : "no")+"<br/>";
                                str += jQuery.i18n.map["crashes.muted"]+":"+((data.muted)? "yes" : "no")+"<br/>";
                            str += '</td>';
                            if(data.custom){
                                str += '<td class="text-left">';
                                for(var i in data.custom){
                                    str += i+': '+data.custom[i]+'<br/>';
                                }
                                str += '</td>';
                            }
                            if(data.logs){
                                str += '<td class="text-left">'+
                                    '<pre>'+data.logs+'</pre>'+
                                '</td>';
                            }
						str += '</tr>'+
						'</table>'+
			'</div>';
		}
		return str;
	},
	switchMetric:function(metric){
		this.curMetric = metric;
		var crashData = countlyCrashes.getGroupData();
		countlyCommon.drawGraph(crashData.dp[this.curMetric], "#dashboard-graph", "bar");
	}
};
$(function() {
    $.fn.dataTableExt.oPagination.four_button = {
        "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
        {
            nFirst = document.createElement( 'span' );
            nPrevious = document.createElement( 'span' );
            nNext = document.createElement( 'span' );
            nLast = document.createElement( 'span' );

            nFirst.innerHTML = "<i class='fa fa-angle-double-left'></i>";
            nPrevious.innerHTML = "<i class='fa fa-angle-left'></i>";
            nNext.innerHTML = "<i class='fa fa-angle-right'></i>";
            nLast.innerHTML = "<i class='fa fa-angle-double-right'></i>";

            nFirst.className = "paginate_button first";
            nPrevious.className = "paginate_button previous";
            nNext.className="paginate_button next";
            nLast.className = "paginate_button last";

            nPaging.appendChild( nFirst );
            nPaging.appendChild( nPrevious );
            nPaging.appendChild( nNext );
            nPaging.appendChild( nLast );

            $(nFirst).click( function () {
                oSettings.oApi._fnPageChange( oSettings, "first" );
                fnCallbackDraw( oSettings );
            } );

            $(nPrevious).click( function() {
                oSettings.oApi._fnPageChange( oSettings, "previous" );
                fnCallbackDraw( oSettings );
            } );

            $(nNext).click( function() {
                oSettings.oApi._fnPageChange( oSettings, "next" );
                fnCallbackDraw( oSettings );
            } );

            $(nLast).click( function() {
                oSettings.oApi._fnPageChange( oSettings, "last" );
                fnCallbackDraw( oSettings );
            } );

            $(nFirst).bind( 'selectstart', function () { return false; } );
            $(nPrevious).bind( 'selectstart', function () { return false; } );
            $(nNext).bind( 'selectstart', function () { return false; } );
            $(nLast).bind( 'selectstart', function () { return false; } );
        },

        "fnUpdate": function ( oSettings, fnCallbackDraw )
        {
            if ( !oSettings.aanFeatures.p )
            {
                return;
            }

            var an = oSettings.aanFeatures.p;
            for ( var i=0, iLen=an.length ; i<iLen ; i++ )
            {
                var buttons = an[i].getElementsByTagName('span');
                if ( oSettings._iDisplayStart === 0 )
                {
                    buttons[0].className = "paginate_disabled_previous";
                    buttons[1].className = "paginate_disabled_previous";
                }
                else
                {
                    buttons[0].className = "paginate_enabled_previous";
                    buttons[1].className = "paginate_enabled_previous";
                }

                if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
                {
                    buttons[2].className = "paginate_disabled_next";
                    buttons[3].className = "paginate_disabled_next";
                }
                else
                {
                    buttons[2].className = "paginate_enabled_next";
                    buttons[3].className = "paginate_enabled_next";
                }
            }
        }
    };

    $.fn.dataTableExt.oApi.fnStandingRedraw = function(oSettings) {
        if(oSettings.oFeatures.bServerSide === false){
            var before = oSettings._iDisplayStart;

            oSettings.oApi._fnReDraw(oSettings);

            // iDisplayStart has been reset to zero - so lets change it back
            oSettings._iDisplayStart = before;
            oSettings.oApi._fnCalculateEnd(oSettings);
        }

        // draw the 'current' page
        oSettings.oApi._fnDraw(oSettings);
    };
    jQuery.fn.dataTableExt.oSort['format-ago-asc']  = function(x, y) {
        return x-y;
    };

    jQuery.fn.dataTableExt.oSort['format-ago-desc']  = function(x, y) {
        return y-x;
    };
    function getFileName(ext){
        var name = "Crash Reports";
        return (name.charAt(0).toUpperCase() + name.slice(1).toLowerCase())+"-"+moment().format("DD-MMM-YYYY")+"."+ext;
    }

    $.extend(true, $.fn.dataTable.defaults, {
        "sDom": '<"dataTable-top"lfpT>t<"dataTable-bottom"i>',
        "bAutoWidth": false,
        "bLengthChange":true,
        "bPaginate":true,
        "sPaginationType": "four_button",
        "iDisplayLength": 50,//(store.get("iDisplayLength")) ? parseInt(store.get("iDisplayLength")) : 50,
        "bDestroy": true,
        "bDeferRender": true,
        "oLanguage": {
			"sZeroRecords": jQuery.i18n.map["common.table.no-data"],
			"sInfoEmpty": jQuery.i18n.map["common.table.no-data"],
			"sEmptyTable": jQuery.i18n.map["common.table.no-data"],
			"sInfo": jQuery.i18n.map["common.showing"],
			"sInfoFiltered": jQuery.i18n.map["common.filtered"],
			"sSearch": jQuery.i18n.map["common.search"],
            "sLengthMenu": jQuery.i18n.map["common.show-items"]+"<input type='number' id='dataTables_length_input'/>"
		},
        "oTableTools": {
            "sSwfPath": countlyGlobal["cdn"]+"javascripts/dom/dataTables/swf/copy_csv_xls.swf",
            "aButtons": [
                {
                    "sExtends": "csv",
                    "sButtonText": jQuery.i18n.map["common.save-to-csv"],
                    "fnClick": function (nButton, oConfig, flash) {
                        var tableCols = $(nButton).parents(".dataTables_wrapper").find(".dataTable").dataTable().fnSettings().aoColumns,
                            tableData = this.fnGetTableData(oConfig).split(/\r\n|\r|\n/g).join('","').split('","'),
                            retStr = "";
                            
                        //check if exported data needs to be processed by some other lib    
                        if(tableCols[0].sExport && app.dataExports[tableCols[0].sExport]){
                            
                            //get data to export
                            var data = app.dataExports[tableCols[0].sExport]();
                            
                            //get all columns
                            var cols = [];
                            for(var i = 0; i < data.length; i++){
                                for(var col in data[i]){
                                     if(cols.indexOf(col) === -1)
                                         cols.push(col);
                                    
                                 }
                            }
                            
                            //generate data in the needed format
                            var tdata = JSON.parse(JSON.stringify(cols));
                            for(var i = 0; i < data.length; i++){
                                for(var j = 0; j < cols.length; j++){
                                    tdata.push('"'+(data[i][cols[j]] || ""));
                                }
                            }
                            
                            tableCols = cols;
                            tableData = tdata;
                        }

                        for (var i = 0;  i < tableData.length; i++) {
                            tableData[i] = tableData[i].replace(/^"/, "");

                            if (i >= tableCols.length) {
                                var colIndex = i % tableCols.length;
                                 
                                if (tableCols[colIndex].sType == "formatted-num") {
                                    tableData[i] = tableData[i].replace(/,/g, "");
                                } else if (tableCols[colIndex].sType == "percent") {
                                    tableData[i] = tableData[i].replace("%", "");
                                } else if (tableCols[colIndex].sType == "format-ago" || tableCols[colIndex].sType == "event-timeline") {
                                    tableData[i] = tableData[i].split("|").pop();
                                }
                            }

                            if ((i + 1) % tableCols.length == 0) {
                                retStr += "\"" + tableData[i] + "\"\r\n";
                            } else {
                                retStr += "\"" + tableData[i] + "\", ";
                            }
                        }
                        flash.setFileName( getFileName("csv") );
                        this.fnSetText(flash, retStr);
                    }
                },
                {
                    "sExtends": "xls",
                    "sButtonText": jQuery.i18n.map["common.save-to-excel"],
                    "fnClick": function (nButton, oConfig, flash) {
                        var tableCols = $(nButton).parents(".dataTables_wrapper").find(".dataTable").dataTable().fnSettings().aoColumns,
                            tableData = this.fnGetTableData(oConfig).split(/\r\n|\r|\n/g).join('\t').split('\t'),
                            retStr = "";
                            
                        //check if exported data needs to be processed by some other lib    
                        if(tableCols[0].sExport && app.dataExports[tableCols[0].sExport]){
                            
                            //get data to export
                            var data = app.dataExports[tableCols[0].sExport]();
                            
                            //get all columns
                            var cols = [];
                            for(var i = 0; i < data.length; i++){
                                for(var col in data[i]){
                                     if(cols.indexOf(col) === -1)
                                         cols.push(col);
                                    
                                 }
                            }
                            
                            //generate data in the needed format
                            var tdata = JSON.parse(JSON.stringify(cols));
                            for(var i = 0; i < data.length; i++){
                                for(var j = 0; j < cols.length; j++){
                                    tdata.push(data[i][cols[j]] || "");
                                }
                            }
                            
                            tableCols = cols;
                            tableData = tdata;
                        }

                        for (var i = 0;  i < tableData.length; i++) {
                            if (i >= tableCols.length) {
                                var colIndex = i % tableCols.length;

                                if (tableCols[colIndex].sType == "formatted-num") {
                                    tableData[i] = parseFloat(tableData[i].replace(/,/g, "")).toLocaleString();
                                } else if (tableCols[colIndex].sType == "percent") {
                                    tableData[i] = parseFloat(tableData[i].replace("%", "")).toLocaleString();
                                } else if (tableCols[colIndex].sType == "numeric") {
                                    tableData[i] = parseFloat(tableData[i]).toLocaleString();
                                } else if (tableCols[colIndex].sType == "format-ago" || tableCols[colIndex].sType == "event-timeline") {
                                    tableData[i] = tableData[i].split("|").pop();
                                }
                            }

                            if ((i + 1) % tableCols.length == 0) {
                                retStr += tableData[i] + "\r\n";
                            } else {
                                retStr += tableData[i] + "\t";
                            }
                        }
                        flash.setFileName( getFileName("xls") );
                        this.fnSetText(flash, retStr);
                    }
                }
            ]
        },
        "fnInitComplete": function(oSettings, json) {
            var saveHTML = "<div class='save-table-data' data-help='help.datatables-export'><i class='fa fa-download'></i></div>",
                searchHTML = "<div class='search-table-data'><i class='fa fa-search'></i></div>",
                tableWrapper = $("#" + oSettings.sTableId + "_wrapper");

            $(saveHTML).insertBefore(tableWrapper.find(".DTTT_container"));
            $(searchHTML).insertBefore(tableWrapper.find(".dataTables_filter"));
            tableWrapper.find(".dataTables_filter").html(tableWrapper.find(".dataTables_filter").find("input").attr("Placeholder",jQuery.i18n.map["common.search"]).clone(true));

            tableWrapper.find(".save-table-data").on("click", function() {
                if ($(this).next(".DTTT_container").css('visibility') == 'hidden') {
                    $(this).next(".DTTT_container").css("visibility", 'visible');
                } else {
                    $(this).next(".DTTT_container").css("visibility", 'hidden');
                }
            });

            tableWrapper.find(".search-table-data").on("click", function() {
                $(this).next(".dataTables_filter").toggle();
                $(this).next(".dataTables_filter").find("input").focus();
            });
            
            if(oSettings.oFeatures.bServerSide){
                tableWrapper.find(".save-table-data").tipsy({gravity:$.fn.tipsy.autoNS, title:function () {
                    return ($(this).data("help")) ? jQuery.i18n.map[$(this).data("help")] : "";
                }, fade:true, offset:5, cssClass:'yellow', opacity:1, html:true});
                tableWrapper.find(".dataTables_length").show();
                tableWrapper.find('#dataTables_length_input').bind( 'change.DT', function(e) {
                    //store.set("iDisplayLength", $(this).val());
                });
            }
            else{
                tableWrapper.find(".dataTables_length").hide();
            }

            //tableWrapper.css({"min-height": tableWrapper.height()});
        },
        fnPreDrawCallback: function(oSettings, json) {
            var tableWrapper = $("#" + oSettings.sTableId + "_wrapper");

            if (tableWrapper.find(".table-placeholder").length == 0) {
                var $placeholder = $('<div class="table-placeholder"><div class="top"></div><div class="header"></div></div>');
                tableWrapper.append($placeholder);
            }

            if (tableWrapper.find(".table-loader").length == 0) {
                tableWrapper.append("<div class='table-loader'></div>");
            }
        },
        fnDrawCallback: function(oSettings) {
            var tableWrapper = $("#" + oSettings.sTableId + "_wrapper");
            tableWrapper.find(".dataTable-bottom").show();
            tableWrapper.find(".table-placeholder").remove();
            tableWrapper.find(".table-loader").remove();
        }
    });

    $.fn.dataTableExt.sErrMode = 'throw';
    countlyCrashes.setGroupData(crash_data);
    window.CrashgroupView.beforeRender();
});

    $(document).on('mouseenter', ".bar-inner", function(e) {
        var number = $(this).parent().next();

        number.text($(this).data("item"));
        number.css({"color":$(this).css("background-color")});
    });

    $(document).on('mouseleave', ".bar-inner", function(e) {
        var number = $(this).parent().next();

        number.text(number.data("item"));
        number.css({"color":$(this).parent().find(".bar-inner:first-child").css("background-color")});
    });
    </script>
</body>
</html>